/*
 *  Copyright 2004 Blandware (http://www.blandware.com)
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package com.blandware.atleap.model.core;

import java.util.*;


/**
 * <p>Represents some resource with binary content. This can be document, image
 * or file.</p>
 * <p>
 * Saved resources may be used in various places, such as pages or menu items.
 * </p>
 * <p>Every Content Resource has a list of {@link Role}s that are allowed to
 * access it. If that list is empty, everyone is allowed to access such Content
 * Resource, otherwise only users that have at least one role from that list can
 * access the Content Resource.</p>
 * <p>
 * Binary data that forms the resource is stored in attached {@link ResourceData}
 * object.
 * </p>
 * <p>
 * For each content resource there's an URI by which it's accessible. For each
 * content resource there are two operations: 'view' and 'download'. Every
 * resource may be downloaded, but only some of them may be viewed.
 * </p>
 * <p>
 * When content resource is created, its type will be determined by uploaded
 * file extension. Currently, there are three resource types: images, documents
 * and files (those that are neither image nor document). For known extensions,
 * also mime type is detected. For all other files mime type is <code>null</code>.
 * </p>
 * <p>
 * As pages, content resources have usage counter that stores number of links
 * to particular content resource.
 * </p>
 * <p><a href="ContentResource.java.html"><i>View Source</i></a>
 * </p>
 * <p/>
 *
 * @author Andrey Grebnev <a href="mailto:andrey.grebnev@blandware.com">&lt;andrey.grebnev@blandware.com&gt;</a>
 * @author Sergey Zubtsovskiy <a href="mailto:sergey.zubtsovskiy@blandware.com">&lt;sergey.zubtsovskiy@blandware.com&gt;</a>
 * @version $Revision: 1.54 $ $Date: 2007/12/17 13:38:25 $
 * @see ContentDocument
 * @see ContentImage
 * @see ResourceData
 * @hibernate.class table="`al_core_resource`" lazy="false"
 * @struts.form include-all="false" extends="BaseForm"
 * @hibernate.cache usage="read-write"
 */
public class ContentResource extends BaseObject {

	//~ Instance variables

    /**
     * The ID of this content resource
     */
	protected Long id;
    /**
     * URI under which this content resource will be accessible
     */
	protected String uri;
    /**
     * Some URL associated with content resource
     */
	protected String altUrl;
    /**
	 * Map of descriptions for different locales
	 */
	protected Map description = new HashMap();
    /**
     * Resource data corresponding to this resource
     */
	protected ResourceData resourceData;
    /**
     * Size of resource data in bytes
     */
	protected Long size;
    /**
     * Mime-type of this resource
     */
	protected String mimeType;
    /**
     * Type of this resource (image, document, file)
     */
	protected String type;
    /**
     * Number of links to this resource
     */
	protected Integer usageCounter;
    /**
     * List od roles which are allowed to access this resource
     */
	protected List roles = new ArrayList();
    /**
     * Version of this resource (used in optimistic locking)
     */
	protected Long version;
    /**
     * Date and time of last update
     */
    protected Date lastUpdatedDatetime = null;

    /**
     * List of CFVs linked to this resource
     */
	protected List linkedContentFieldValues = new ArrayList();
    /**
     * List of menu items linked to this resource
     */
	protected List linkedMenuItems = new ArrayList();

    /**
     * List of sequence items that point to this content resource
     */
	protected List sequenceItems = new ArrayList();

    //~ Methods

	/**
	 * Returns the id of this content resource
	 *
	 * @return id
	 * @hibernate.id column="`id`"
	 * generator-class="increment" unsaved-value="null"
	 * @struts.form-field
	 */
	public Long getId() {
		return id;
	}

    /**
     * Sets id of this content resource
     *
     * @param id the id
     */
	public void setId(Long id) {
		this.id = id;
	}

	/**
	 * Returns the URI of the resource. Usually it is the name with extension.
	 *
	 * @return URI
	 * @hibernate.property
	 * @hibernate.column name="`uri`" not-null="true" unique="true" length="252"
	 * @struts.form-field
	 * @struts.validator type="required"
	 * @struts.validator type="mask" msgkey="core.contentResource.errors.uri"
	 * @struts.validator-args arg0resource="core.contentResource.form.uri"
	 * @struts.validator-var name="mask" value="^(\/[a-zA-Z0-9\-_\040\.]+)+\.[a-zA-Z0-9]+$"
	 */
	public String getUri() {
		return uri;
	}

    /**
     * Sets the URI of the resource
     *
     * @param uri the URI
     */
	public void setUri(String uri) {
		this.uri = uri;
	}

    /**
     * Returns alternative URL associated with content resource.
     *
     * @return alternative URL
     * @hibernate.property
	 * @hibernate.column name="`alt_url`" not-null="false" unique="false" length="252"
	 * @struts.form-field
     */
    public String getAltUrl() {
        return altUrl;
    }

    /**
     * Sets alternative URL associated with content resource.
     *
     * @param altUrl alternative URL to set
     */
    public void setAltUrl(String altUrl) {
        this.altUrl = altUrl;
    }

    /**
	 * Returns mapping from locale identifiers to descriptions of this resource.
	 *
	 * @return mapping from locale identifiers to descriptions
	 * @struts.form-field
	 * @hibernate.map table="`al_core_resource_description`" lazy="true" cascade="all" outer-join="false"
	 * @hibernate.collection-key column="`id`"
	 * @hibernate.collection-index column="`locale_identifier`" type="string" length="10"
	 * @hibernate.collection-element type="string" column="`description`" not-null="false" length="252"
	 */
	public Map getDescription() {
		return description;
	}

    /**
     * Sets mapping from locale identifiers to descriptions of this resource.
     *
     * @param description mapping from locale identifiers to descriptions
     */
	public void setDescription(Map description) {
		this.description = description;
	}

    /**
     * Gets resource data that holds binary data owned by this content resource
     *
	 * @return the resource data
	 * @hibernate.one-to-one class="com.blandware.atleap.model.core.ResourceData" constrained="true" cascade="delete" outer-join="false" lazy="false"
	 */
	public ResourceData getResourceData() {
		return resourceData;
	}

    /**
     * Sets resource data that holds binary data owned by this content resource
     *
     * @param resourceData the resource data
     */
	public void setResourceData(ResourceData resourceData) {
		this.resourceData = resourceData;
	}

	/**
	 * Gets size of resource (that's the same as size of resource data in bytes)
	 *
	 * @return size of resource
	 * @hibernate.property
	 * @hibernate.column name="`data_size`" not-null="true" unique="false"
     * @struts.form-field
     * @struts.validator type="long"
	 */
	public Long getSize() {
		return size;
	}

    /**
     * Sets size of resource
     *
     * @param size size of resource
     */
	public void setSize(Long size) {
		this.size = size;
	}

	/**
	 * Returns mime-type of resource content (e.g. 'image/jpeg');
	 *
	 * @return mime-type
	 * @hibernate.property
	 * @hibernate.column name="`mimetype`" not-null="false" unique="false" length="252"
     * @struts.form-field
	 */
	public String getMimeType() {
		return mimeType;
	}

    /**
     * Sets mime-type of resource content
     *
     * @param mimeType the mime-type to set
     */
	public void setMimeType(String mimeType) {
		this.mimeType = mimeType;
	}

	/**
	 * Returns type of resource content (e.g. 'image');
	 *
	 * @return type
	 * @hibernate.property
	 * @hibernate.column name="`type`" not-null="true" unique="false" length="252"
	 */
	public String getType() {
		return type;
	}

    /**
     * Sets type of resource content
     *
     * @param type the type to set
     */
	public void setType(String type) {
		this.type = type;
	}

	/**
     * Gets usage counter for this content resource (that is a number of links
     * to this resource)
     *
	 * @return usage counter
	 * @hibernate.property column="`usage_counter`" not-null="false"
	 */
	public Integer getUsageCounter() {
		return usageCounter;
	}

    /**
     * Sets usage counter for this content resource (that is a number of links
     * to this resource)
     *
     * @param usageCounter new usage counter value
     */
	public void setUsageCounter(Integer usageCounter) {
		this.usageCounter = usageCounter;
	}

	/**
	 * Gets list of roles that are assigned to this content resource
	 *
	 * @return list of roles
     * @hibernate.bag table="`al_core_resource_role`" cascade="none" lazy="true" inverse="false" outer-join="false"
	 * @hibernate.collection-key column="`resource_id`"
	 * @hibernate.collection-many-to-many class="com.blandware.atleap.model.core.Role"
	 * column="`rolename`" outer-join="false"
	 * @hibernate.cache usage="read-write"
	 */
	public List getRoles() {
		return roles;
	}

    /**
     * Sets list of roles that are assigned to this content resource
     *
     * @param roles list of roles
     */
	public void setRoles(List roles) {
		this.roles = roles;
	}

	/**
	 * Gets all resource roles, represented as string
	 *
	 * @return roles separated with commas
	 */
	public String getRolesAsString() {
		StringBuffer roles = new StringBuffer();
		if ( this.roles != null && this.roles.size() > 0 ) {
			for ( Iterator i = this.roles.iterator(); i.hasNext(); ) {
				Role role = (Role) i.next();
				roles.append(role.getTitle());
				if ( i.hasNext() ) {
					roles.append(", ");
				}
			}
		}
		return roles.toString();
	}

    /**
     * Adds a connection between this content resource and a given role
     *
     * @param role the role to be connected with
     */
    public void addRole(Role role) {
        if ( !role.getResources().contains(this) ) {
            role.getResources().add(this);
        }
        if ( !getRoles().contains(role) ) {
            getRoles().add(role);
        }
    }

    /**
     * Removes a connection between this content resource and a given role
     *
     * @param role the role
     */
    public void removeRole(Role role) {
        role.getResources().remove(this);
        getRoles().remove(role);
    }


	/**
	 * Gets list of CFVs this resource is linked with
	 *
     * @return list of CFVs
     * @hibernate.bag table="`al_core_field_value_resource`" cascade="none" lazy="true" inverse="false" outer-join="false"
	 * @hibernate.collection-key column="`resource_id`"
	 * @hibernate.collection-many-to-many class="com.blandware.atleap.model.core.ContentFieldValue" column="`field_value_id`" outer-join="false"
	 */
	public List getLinkedContentFieldValues() {
		return linkedContentFieldValues;
	}

    /**
     * Sets list of CFVs this resource is linked with
     *
     * @param linkedContentFieldValues list of CFVs
     */
	public void setLinkedContentFieldValues(List linkedContentFieldValues) {
		this.linkedContentFieldValues = linkedContentFieldValues;
	}

	/**
	 * Gets list of menu items this context resource is linked with
	 *
     * @return list of menu items
     * @hibernate.bag table="`al_core_menu_item_resource`" cascade="none" lazy="true" inverse="false" outer-join="false"
	 * @hibernate.collection-key column="`resource_id`"
	 * @hibernate.collection-many-to-many class="com.blandware.atleap.model.core.MenuItem" column="`menu_item_id`" outer-join="false"
	 */
	public List getLinkedMenuItems() {
		return linkedMenuItems;
	}

    /**
     * Sets list of menu items this content resource is linked with
     *
     * @param linkedMenuItems list of menu items
     */
	public void setLinkedMenuItems(List linkedMenuItems) {
		this.linkedMenuItems = linkedMenuItems;
	}

	/**
	 * Returns true if this resource is in use, i.e. there are links on it from content field values or menu items
	 * or its usage counter is greater than zero
     *
	 * @return <code>true</code> if this resource is in use
	 */
	public boolean isInUse() {
		return !linkedContentFieldValues.isEmpty() || !linkedMenuItems.isEmpty() || usageCounter.intValue() > 0;
	}

    /**
     * Returns whether there are some objects linked to this page by URI that
     * cannot be modified to have correct links when this page URI is changed
     *
     * @return whether there are unmodifiable linked objects
     */
    public boolean doUnmodifiableLinkedObjectsExist() {
        for (Iterator i = linkedMenuItems.iterator(); i.hasNext();) {
            MenuItem menuItem = (MenuItem) i.next();
            if (!menuItem.isDynamic()) {
                return true;
            }
        }
        return false;
    }    

	/**
	 * Returns version of this content resource
	 *
	 * @return version
	 * @struts.form-field
	 * @hibernate.version column="`version`" type="long" unsaved-value="null"
	 */
	public Long getVersion() {
		return version;
	}

    /**
     * Sets version of this content resource
     *
     * @param version the new version
     */
	public void setVersion(Long version) {
		this.version = version;
	}

    /**
     * Gets date/time when this content resource was created/last updated
     *
     * @return last updated data/time
     * @hibernate.property
     * @hibernate.column name="`last_updated`" not-null="true" unique="false"
     * @struts.form-field
     * @struts.validator type="customdate"
     */
    public Date getLastUpdatedDatetime() {
        return lastUpdatedDatetime;
    }

    /**
     * Sets date/time when this content resource was created/last updated
     *
     * @param lastUpdatedDatetime last updated data/time
     */
    public void setLastUpdatedDatetime(Date lastUpdatedDatetime) {
        this.lastUpdatedDatetime = lastUpdatedDatetime;
    }

	/**
	 * Returns the list of sequence items that point to this content resource.
	 *
	 * @return the list of sequence items
	 * @hibernate.bag name="sequenceItems" inverse="true" lazy="true" cascade="delete" outer-join="false"
	 * @hibernate.collection-key column="`resource_id`"
	 * @hibernate.collection-one-to-many class="com.blandware.atleap.model.core.SequenceItem"
	 */
	protected List getSequenceItems() {
		return sequenceItems;
	}

    /**
     * Sets list of sequence items that point to this content resource.
     *
     * @param sequenceItems the list of sequence items
     */
	protected void setSequenceItems(List sequenceItems) {
		this.sequenceItems = sequenceItems;
	}

    public boolean equals(Object o) {
		if ( this == o ) {
			return true;
		}
		if ( !(o instanceof ContentResource) ) {
			return false;
		}

		final ContentResource contentResource = (ContentResource) o;

		if ( uri != null ? !uri.equals(contentResource.uri) : contentResource.uri != null ) {
			return false;
		}

		return true;
	}

	public int hashCode() {
		return (uri != null ? uri.hashCode() : 0);
	}

}
